package edu.cs.cs160.storytime;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11Ext;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.opengl.GLSurfaceView.Renderer;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class StoryRenderer implements Renderer {

	public final static int CENTER = 0;
	public final static int LEFT = -1;
	public final static int RIGHT = 1;
	public final static int FARRIGHT = 2;
	public final static int FARLEFT = -2;
	public final static int MOVING = Integer.MAX_VALUE;
	private final static float speed = 20;
	private int moveRight;
	private int moveLeft;
	private Context myLibrary;
	private int georgeLocation;
	private int[] textures = new int[10];
	private double rotation;
	private float translation;
	private float size;
	
	private float vertices[] = {
			//Vertices according to faces
    		-1.0f, -1.0f, 1.0f, //Vertex 0
    		1.0f, -1.0f, 1.0f,  //v1
    		-1.0f, 1.0f, 1.0f,  //v2
    		1.0f, 1.0f, 1.0f,   //v3
    		
    		1.0f, -1.0f, 1.0f,	//...
    		1.0f, -1.0f, -1.0f,    		
    		1.0f, 1.0f, 1.0f,
    		1.0f, 1.0f, -1.0f,
    		
    		1.0f, -1.0f, -1.0f,
    		-1.0f, -1.0f, -1.0f,    		
    		1.0f, 1.0f, -1.0f,
    		-1.0f, 1.0f, -1.0f,
    		
    		-1.0f, -1.0f, -1.0f,
    		-1.0f, -1.0f, 1.0f,    		
    		-1.0f, 1.0f, -1.0f,
    		-1.0f, 1.0f, 1.0f,
    		
    		-1.0f, -1.0f, -1.0f,
    		1.0f, -1.0f, -1.0f,    		
    		-1.0f, -1.0f, 1.0f,
    		1.0f, -1.0f, 1.0f,
    		
    		-1.0f, 1.0f, 1.0f,
    		1.0f, 1.0f, 1.0f,    		
    		-1.0f, 1.0f, -1.0f,
    		1.0f, 1.0f, -1.0f,
								};

/** The initial texture coordinates (u, v) */	
	private float texture[] = {    		
		//Mapping coordinates for the vertices
    		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,
     		
     		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,
    		
     		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,
    		
     		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,
    		
     		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,
    		
     		0.0f, 1.0f,
    		1.0f, 1.0f,
    		0.0f, 0.0f,
     		1.0f, 0.0f,

    							};

/** The initial indices definition */	
	private byte indices[] = {
			//Faces definition
    		0,1,3, 0,3,2, 			//Face front
    		4,5,7, 4,7,6, 			//Face right
    		8,9,11, 8,11,10, 		//... 
    		12,13,15, 12,15,14, 	
    		16,17,19, 16,19,18, 	
    		20,21,23, 20,23,22, 	
								};
	
	private FloatBuffer vertexBuffer;
	private FloatBuffer textureBuffer;
	private ByteBuffer indexBuffer;
	
	public StoryRenderer(Context s)
	{
		georgeLocation = CENTER;
		moveLeft = 0;
		moveRight = 0;
		
		
		myLibrary = s;
		ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuf.order(ByteOrder.nativeOrder());
		vertexBuffer = byteBuf.asFloatBuffer();
		vertexBuffer.put(vertices);
		vertexBuffer.position(0);

		//
		byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
		byteBuf.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuf.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);

		//
		indexBuffer = ByteBuffer.allocateDirect(indices.length);
		indexBuffer.put(indices);
		indexBuffer.position(0);
	}
	
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		
        //gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[4]);

        // Draw using the DrawTexture extension.
        //((GL11Ext) gl).glDrawTexfOES(0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
        
		
		if(moveRight > 0)
		{
			translation -= (3.0f/speed);
			size += (1.0f/speed);
			if(moveRight == 1)
			{
				georgeLocation--;
				translation = 0.0f;
				size = 0.0f;
			}
			moveRight--;
		}
		if(moveLeft > 0)
		{
			translation += (3.0f/speed);
			size += (1.0f/speed);
			if(moveLeft == 1)
			{
				georgeLocation++;
				translation = 0.0f;
				size = 0.0f;
			}
			moveLeft--;
		}
		
		if(georgeLocation == CENTER)
		{
			drawBook(gl, CENTER, 0);
			drawBook(gl, LEFT, 1);
			drawBook(gl, RIGHT, 2);
			drawBook(gl, FARRIGHT, 3);
		}
		else if(georgeLocation == LEFT)
		{
			drawBook(gl, LEFT, 0);
			drawBook(gl, FARLEFT, 1);
			drawBook(gl, CENTER, 2);
			drawBook(gl, RIGHT, 3);
			
		}
		else if(georgeLocation == RIGHT)
		{
			drawBook(gl, RIGHT, 0);
			drawBook(gl, CENTER, 1);
			drawBook(gl, FARRIGHT, 2);
		}
		else if(georgeLocation == FARLEFT)
		{
			drawBook(gl, FARLEFT, 0);
			drawBook(gl, LEFT, 2);
			drawBook(gl, CENTER, 3);
		}
		/*else if(moveLeft)
		{
			
		}*/
	}
	
	private void drawBook(GL10 gl, int location, int book)
	{
		
		gl.glLoadIdentity();
		
		
		if(location == CENTER)
		{
			gl.glTranslatef(0.0f + translation, 0.0f, -5.0f - size);
		}
		else if(location == LEFT)
		{
			gl.glTranslatef(-3.0f + translation, 0.0f, -6.0f + size);
			//gl.glRotatef(0.7f, 0.0f, 0.0f, 0.0f);
		}
		else if(location == RIGHT)
		{
			gl.glTranslatef(3.0f + translation, 0.0f, -6.0f + size);
			//gl.glRotatef(-0.7f, 0.0f, 0.0f, 0.0f);
		}
		else if(location == FARRIGHT)
		{
			gl.glTranslatef(6.0f + translation, 0.0f, -6.0f);
			//gl.glRotatef(0.3f, 0.0f, 0.0f, 0.0f);
		}
		else if(location == FARLEFT)
		{
			gl.glTranslatef(-6.0f + translation, 0.0f, -6.0f);
		}
		//gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f);
		
		
		
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[book]);
		
		//Point to our buffers
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

		//Set the face rotation
		gl.glFrontFace(GL10.GL_CCW);
		
		//Enable the vertex and texture state
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		//Draw the vertices as triangles, based on the Index Buffer information
		gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
		
		//Disable the client state before leaving
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		
		
		
	}
	
	/*private void drawGeorge(GL10 gl, int location)  {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);	
		gl.glLoadIdentity();
		System.out.println("ondrawframe");
		
		if(location == CENTER)
		{
			gl.glTranslatef(0.0f, 0.0f, -5.0f);
		}
		else if(location == LEFT)
		{
			gl.glTranslatef(-0.5f, 0.0f, -5.0f);
			gl.glRotatef(1.0f, 0.0f, 0.0f, 0.0f);
		}
		else if(location == RIGHT)
		{
			gl.glTranslatef(0.5f, 0.0f, -5.0f);
			gl.glRotatef(-1.0f, 0.0f, 0.0f, 0.0f);
		}
		//gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f);
		
		
		
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
		
		//Point to our buffers
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

		//Set the face rotation
		gl.glFrontFace(GL10.GL_CCW);
		
		//Enable the vertex and texture state
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		//Draw the vertices as triangles, based on the Index Buffer information
		gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
		
		//Disable the client state before leaving
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
	}*/

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
		if(height == 0) { 						//Prevent A Divide By Zero By
			height = 1; 						//Making Height Equal One
		}
		gl.glViewport(0, 0, width, height); 	//Reset The Current Viewport
		gl.glMatrixMode(GL10.GL_PROJECTION); 	//Select The Projection Matrix
		gl.glLoadIdentity(); 					//Reset The Projection Matrix

		//Calculate The Aspect Ratio Of The Window
		GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);

		gl.glMatrixMode(GL10.GL_MODELVIEW); 	//Select The Modelview Matrix
		gl.glLoadIdentity(); 					//Reset The Modelview Matrix
		

	} 

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		loadGLTexture(gl, myLibrary);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glShadeModel(GL10.GL_SMOOTH); 			//Enable Smooth Shading
		gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 	//White Background
		gl.glClearDepthf(1.0f); 					//Depth Buffer Setup
		gl.glEnable(GL10.GL_DEPTH_TEST); 			//Enables Depth Testing
		gl.glDepthFunc(GL10.GL_LEQUAL); 			//The Type Of Depth Testing To Do
		
		//Really Nice Perspective Calculations
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
	}

	
	public void loadGLTexture(GL10 gl, Context context) {
		//Get the texture from the Android resource directory
		loadGLTextureParts(gl, context, context.getResources().openRawResource(R.drawable.libcover_george), 0);
		loadGLTextureParts(gl, context, context.getResources().openRawResource(R.drawable.libcover_iforgot), 1);
		loadGLTextureParts(gl, context, context.getResources().openRawResource(R.drawable.libcover_excuse), 2);
		loadGLTextureParts(gl, context, context.getResources().openRawResource(R.drawable.libcover_goingtobed), 3);
		//loadGLTextureParts(gl, context, context.getResources().openRawResource(R.drawable.bookshelfbackground), 4);
	}
		
	private void loadGLTextureParts(GL10 gl, Context context, InputStream is, int n)  {
		Bitmap bitmap = null;
		try {
			//BitmapFactory is an Android graphics utility for images
			bitmap = BitmapFactory.decodeStream(is);
			if(bitmap == null)
			{
				gl.glColor4f(0.1f, 0.1f, 0.3f, 1.0f);
				return;
			}

		} finally {
			//Always clear and close
			try {
				is.close();
				is = null;
			} catch (IOException e) {
			}
		}
		

		//Generate one texture pointer...
		gl.glGenTextures(1, textures, n);
		//...and bind it to our array
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[n]);
		
		//Create Nearest Filtered Texture
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

		//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
		
		//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
		
		//Clean up
		bitmap.recycle();
	}

	public void goRight() {
		/*if(georgeLocation == CENTER)
		{
			georgeLocation = LEFT;
			//moveLeft = true;
		}
		else if(georgeLocation == RIGHT)
		{
			georgeLocation = CENTER;
		}
		else if(georgeLocation == FARRIGHT)
		{
			georgeLocation = RIGHT;
		}
		else if(georgeLocation == LEFT)
		{
			georgeLocation = FARLEFT;
		}*/
		if(georgeLocation > -2 && moveRight == 0 && moveLeft == 0)
		{
			moveRight = (int)speed;
			//georgeLocation -= 1;
			
		}
		
	}

	public void goLeft() {
		if(georgeLocation < 1 && moveRight == 0 && moveLeft == 0)
		{
			moveLeft = (int)speed;
			//georgeLocation += 1;
		}
		/*if(georgeLocation == CENTER)
		{
			moveLeft = true;
		}
		else if(georgeLocation == LEFT)
		{
			moveLeft = true;
		}*/
	}
	
	public int getGeorgeLocation()
	{
		return georgeLocation;
	}
}
